package mspbots.next.ticket.core.grader.interceptor;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import mspbots.next.ticket.core.grader.AbstractGradeRuleAdapter;
import mspbots.next.ticket.core.grader.GradeRuleInterceptorRegistration;
import mspbots.next.ticket.core.points.PointResult;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;


@Log4j2
@Service(value = "UPDATE_TIME_GRADE_RULE")
public class UpdateTimeGradeRuleInterceptor extends AbstractGradeRuleAdapter {

    private static final String RULE_KEY = "TicketLastUpdated";
    private List<UpdateTimeParam> params;

    @Override
    public Mono<GradeRuleInterceptorRegistration> prepare(GradeRuleInterceptorRegistration gradeRuleInterceptorRegistration) {
        return Flux.just()
                .doFinally(r ->
                    this.params = super.objectMapper
                            .convertValue(gradeRuleInterceptorRegistration.getRule().getParams(), new TypeReference<>() {
                            })
                )
                .then(Mono.just(gradeRuleInterceptorRegistration));
    }

    @Override
    public Mono<PointResult> scoring(JsonNode ticket) {
        LocalDateTime lastUpdated = super.getDateTimeValue(ticket.get("_info").get("lastUpdated"));
        int order = params.stream().filter(UpdateTimeParam::isSelected)
                .filter(item -> !ObjectUtils.isEmpty(item.getHours()))
                .filter(item -> lastUpdated.isBefore(LocalDateTime.now().minusHours(item.getHours())))
                .mapToInt(UpdateTimeParam::getPoints).sum();
        Duration duration = Duration.between(lastUpdated, LocalDateTime.now()).abs();
        String ticketHours = String.format("%.2f", (float) duration.toMinutes() / 60);
        return Mono.just(PointResult.withDefault().point(order)
                .detail(PointResult.Detail.with(order, Map.of("lastUpdated", lastUpdated,"time",ticketHours + " hours/"), RULE_KEY)));
    }

    @Data
    private static class UpdateTimeParam {
        private String title;
        private Integer points;
        private Integer hours;
        private boolean selected;
    }

}
